// *****************************************************************************
// *****************************************************************************
// Copyright 2012 - 2013, Cadence Design Systems
//
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8.
//
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
//
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
//
//  $Author: dell $
//  $Revision: #1 $
//  $Date: 2020/09/29 $
//  $State:  $
// *****************************************************************************
// *****************************************************************************

#include "lefiNonDefault.hpp"

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include "lefiDebug.hpp"
#include "lefiKRDefs.hpp"
#include "lefrCallBacks.hpp"
#include "lefrData.hpp"
#include "lex.h"

BEGIN_LEF_PARSER_NAMESPACE

// 6/16/2000 - Wanda da Rosa
// Make these variables in globals.  Can't use those defined
// in the class because it generates warning when it casts.
// Can't assign for example lefrViaCbkFnType to oldViaCbk_
// in the class because it requires to include lefrReader.hpp
// in lefiNonDefault.hpp.  But in lefrReader.hpp, it requires
// include lefiNonDefault.hpp, this creates a loop and is
// problematic...

// *****************************************************************************
// lefiNonDefault
// *****************************************************************************

lefiNonDefault::lefiNonDefault()
{
  Init();
}

void lefiNonDefault::Init()
{
  nameSize_ = 16;
  name_ = (char*) lefMalloc(16);

  layersAllocated_ = 2;
  numLayers_ = 0;
  layerName_ = (char**) lefMalloc(sizeof(char*) * 2);
  width_ = (double*) lefMalloc(sizeof(double) * 2);
  diagWidth_ = (double*) lefMalloc(sizeof(double) * 2);
  spacing_ = (double*) lefMalloc(sizeof(double) * 2);
  wireExtension_ = (double*) lefMalloc(sizeof(double) * 2);
  resistance_ = (double*) lefMalloc(sizeof(double) * 2);
  capacitance_ = (double*) lefMalloc(sizeof(double) * 2);
  edgeCap_ = (double*) lefMalloc(sizeof(double) * 2);
  hasWidth_ = (char*) lefMalloc(sizeof(char) * 2);
  hasDiagWidth_ = (char*) lefMalloc(sizeof(char) * 2);
  hasSpacing_ = (char*) lefMalloc(sizeof(char) * 2);
  hasWireExtension_ = (char*) lefMalloc(sizeof(char) * 2);
  hasResistance_ = (char*) lefMalloc(sizeof(char) * 2);
  hasCapacitance_ = (char*) lefMalloc(sizeof(char) * 2);
  hasEdgeCap_ = (char*) lefMalloc(sizeof(char) * 2);

  allocatedVias_ = 2;
  numVias_ = 0;
  viaRules_ = (lefiVia**) lefMalloc(sizeof(lefiVia*) * 2);

  allocatedSpacing_ = 2;
  numSpacing_ = 0;
  spacingRules_ = (lefiSpacing**) lefMalloc(sizeof(lefiSpacing*) * 2);

  numProps_ = 0;
  propsAllocated_ = 1;
  names_ = (char**) lefMalloc(sizeof(char*));
  values_ = (char**) lefMalloc(sizeof(char*));
  dvalues_ = (double*) lefMalloc(sizeof(double));
  types_ = (char*) lefMalloc(sizeof(char));

  hardSpacing_ = 0;
  numUseVias_ = 0;  // Won't be allocated until they are used
  allocatedUseVias_ = 0;
  numUseViaRules_ = 0;
  allocatedUseViaRules_ = 0;
  numMinCuts_ = 0;
  allocatedMinCuts_ = 0;
}

void lefiNonDefault::Destroy()
{
  clear();

  lefFree(name_);

  lefFree(layerName_);
  lefFree(width_);
  lefFree(diagWidth_);
  lefFree(spacing_);
  lefFree(wireExtension_);
  lefFree(resistance_);
  lefFree(capacitance_);
  lefFree(edgeCap_);
  lefFree(hasWidth_);
  lefFree(hasDiagWidth_);
  lefFree(hasSpacing_);
  lefFree(hasWireExtension_);
  lefFree(hasResistance_);
  lefFree(hasCapacitance_);
  lefFree(hasEdgeCap_);

  lefFree(viaRules_);

  lefFree(spacingRules_);
  lefFree(names_);
  lefFree(values_);
  lefFree(dvalues_);
  lefFree(types_);
  if (allocatedUseVias_) {
    lefFree(useViaName_);
  }
  if (allocatedUseViaRules_) {
    lefFree(useViaRuleName_);
  }
  if (allocatedMinCuts_) {
    lefFree(cutLayerName_);
    lefFree(numCuts_);
  }
  allocatedUseVias_ = 0;
  allocatedUseViaRules_ = 0;
  allocatedMinCuts_ = 0;
}

lefiNonDefault::~lefiNonDefault()
{
  Destroy();
}

void lefiNonDefault::clear()
{
  int i;
  lefiSpacing* sr;
  lefiVia* vr;

  for (i = 0; i < numProps_; i++) {
    lefFree(names_[i]);
    lefFree(values_[i]);
    dvalues_[i] = 0;
  }
  numProps_ = 0;
  for (i = 0; i < numLayers_; i++) {
    lefFree(layerName_[i]);
    layerName_[i] = nullptr;
  }
  numLayers_ = 0;
  for (i = 0; i < numVias_; i++) {
    vr = viaRules_[i];
    vr->Destroy();
    lefFree(viaRules_[i]);
    viaRules_[i] = nullptr;
  }
  numVias_ = 0;
  for (i = 0; i < numSpacing_; i++) {
    sr = spacingRules_[i];
    sr->Destroy();
    lefFree(spacingRules_[i]);
    spacingRules_[i] = nullptr;
  }
  numSpacing_ = 0;

  hardSpacing_ = 0;
  for (i = 0; i < numUseVias_; i++) {
    lefFree(useViaName_[i]);
  }
  numUseVias_ = 0;
  for (i = 0; i < numUseViaRules_; i++) {
    lefFree(useViaRuleName_[i]);
  }
  numUseViaRules_ = 0;
  for (i = 0; i < numMinCuts_; i++) {
    lefFree(cutLayerName_[i]);
  }
  numMinCuts_ = 0;
}

void lefiNonDefault::addViaRule(lefiVia* v)
{
  if (numVias_ == allocatedVias_) {
    int i;
    lefiVia** nv;

    if (allocatedVias_ == 0) {
      allocatedVias_ = 2;
    } else {
      allocatedVias_ *= 2;
    }
    nv = (lefiVia**) lefMalloc(sizeof(lefiVia*) * allocatedVias_);
    for (i = 0; i < numVias_; i++) {
      nv[i] = viaRules_[i];
    }
    lefFree(viaRules_);
    viaRules_ = nv;
  }
  viaRules_[numVias_++] = v->clone();
}

void lefiNonDefault::addSpacingRule(lefiSpacing* s)
{
  if (numSpacing_ == allocatedSpacing_) {
    int i;
    lefiSpacing** ns;

    if (allocatedSpacing_ == 0) {
      allocatedSpacing_ = 2;
    } else {
      allocatedSpacing_ *= 2;
    }
    ns = (lefiSpacing**) lefMalloc(sizeof(lefiSpacing*) * allocatedSpacing_);
    for (i = 0; i < numSpacing_; i++) {
      ns[i] = spacingRules_[i];
    }
    lefFree(spacingRules_);
    spacingRules_ = ns;
  }
  spacingRules_[numSpacing_++] = s->clone();
}

void lefiNonDefault::setName(const char* name)
{
  int len = strlen(name) + 1;
  clear();

  // Use our callback functions because a via and spacing
  // rule is really part of the non default section.
  // oldViaCbk_ = (void*)lefrViaCbk;
  // oldSpacingCbk_ = (void*)lefrSpacingCbk;
  // oldSpacingBeginCbk_ = (void*)lefrSpacingBeginCbk;
  // oldSpacingEndCbk_ = (void*)lefrSpacingEndCbk;
  // oldUserData_ = lefrGetUserData();
  // oldViaCbk = lefCallbacks->ViaCbk;
  // oldSpacingCbk = lefCallbacks->SpacingCbk;
  // oldSpacingBeginCbk = lefCallbacks->SpacingBeginCbk;
  // oldSpacingEndCbk = lefCallbacks->SpacingEndCbk;
  // lefCallbacks->ViaCbk = lefiNonDefaultViaCbk;
  // lefCallbacks->SpacingCbk = lefiNonDefaultSpacingCbk;
  // lefCallbacks->SpacingBeginCbk = 0;
  // lefCallbacks->SpacingEndCbk = 0;
  // pcr 909010, instead of saving the pointer in userData,
  // save it in the global lefData->nd.
  // lefrSetUserData((lefiUserData)this);

  lefData->nd = this;

  if (len > nameSize_) {
    lefFree(name_);
    name_ = (char*) lefMalloc(len);
    nameSize_ = len;
  }
  strcpy(name_, CASE(name));
}

void lefiNonDefault::addLayer(const char* name)
{
  int len = strlen(name) + 1;
  if (numLayers_ == layersAllocated_) {
    int i;
    char** newl;
    double* neww;
    double* newd;
    double* news;
    double* newe;
    double* newc;
    double* newr;
    double* newec;
    char* newhw;
    char* newhd;
    char* newhs;
    char* newhe;
    char* newhc;
    char* newhr;
    char* newhec;

    if (layersAllocated_ == 0) {
      layersAllocated_ = 2;
    } else {
      layersAllocated_ *= 2;
    }
    newl = (char**) lefMalloc(sizeof(char*) * layersAllocated_);
    newe = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    neww = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    newd = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    news = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    newc = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    newr = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    newec = (double*) lefMalloc(sizeof(double) * layersAllocated_);
    newhe = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhw = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhd = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhs = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhc = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhr = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    newhec = (char*) lefMalloc(sizeof(char) * layersAllocated_);
    for (i = 0; i < numLayers_; i++) {
      newl[i] = layerName_[i];
      neww[i] = width_[i];
      newd[i] = diagWidth_[i];
      news[i] = spacing_[i];
      newe[i] = wireExtension_[i];
      newc[i] = capacitance_[i];
      newr[i] = resistance_[i];
      newec[i] = edgeCap_[i];
      newhe[i] = hasWireExtension_[i];
      newhw[i] = hasWidth_[i];
      newhd[i] = hasDiagWidth_[i];
      newhs[i] = hasSpacing_[i];
      newhc[i] = hasCapacitance_[i];
      newhr[i] = hasResistance_[i];
      newhec[i] = hasEdgeCap_[i];
    }
    lefFree(layerName_);
    lefFree(width_);
    lefFree(diagWidth_);
    lefFree(spacing_);
    lefFree(wireExtension_);
    lefFree(capacitance_);
    lefFree(resistance_);
    lefFree(edgeCap_);
    lefFree(hasWireExtension_);
    lefFree(hasWidth_);
    lefFree(hasDiagWidth_);
    lefFree(hasSpacing_);
    lefFree(hasCapacitance_);
    lefFree(hasResistance_);
    lefFree(hasEdgeCap_);
    layerName_ = newl;
    width_ = neww;
    diagWidth_ = newd;
    spacing_ = news;
    wireExtension_ = newe;
    capacitance_ = newc;
    resistance_ = newr;
    edgeCap_ = newec;
    hasWidth_ = newhw;
    hasDiagWidth_ = newhd;
    hasSpacing_ = newhs;
    hasWireExtension_ = newhe;
    hasCapacitance_ = newhc;
    hasResistance_ = newhr;
    hasEdgeCap_ = newhec;
  }
  layerName_[numLayers_] = (char*) lefMalloc(len);
  strcpy(layerName_[numLayers_], CASE(name));
  width_[numLayers_] = 0.0;
  diagWidth_[numLayers_] = 0.0;
  spacing_[numLayers_] = 0.0;
  wireExtension_[numLayers_] = 0.0;
  capacitance_[numLayers_] = 0.0;
  resistance_[numLayers_] = 0.0;
  edgeCap_[numLayers_] = 0.0;
  hasWidth_[numLayers_] = '\0';
  hasDiagWidth_[numLayers_] = '\0';
  hasSpacing_[numLayers_] = '\0';
  hasWireExtension_[numLayers_] = '\0';
  hasCapacitance_[numLayers_] = '\0';
  hasResistance_[numLayers_] = '\0';
  hasEdgeCap_[numLayers_] = '\0';
  numLayers_ += 1;
}

void lefiNonDefault::addWidth(double num)
{
  width_[numLayers_ - 1] = num;
  hasWidth_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addDiagWidth(double num)
{
  diagWidth_[numLayers_ - 1] = num;
  hasDiagWidth_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addSpacing(double num)
{
  spacing_[numLayers_ - 1] = num;
  hasSpacing_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addWireExtension(double num)
{
  wireExtension_[numLayers_ - 1] = num;
  hasWireExtension_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addCapacitance(double num)
{
  capacitance_[numLayers_ - 1] = num;
  hasCapacitance_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addResistance(double num)
{
  resistance_[numLayers_ - 1] = num;
  hasResistance_[numLayers_ - 1] = 1;
}

void lefiNonDefault::addEdgeCap(double num)
{
  edgeCap_[numLayers_ - 1] = num;
  hasEdgeCap_[numLayers_ - 1] = 1;
}

void lefiNonDefault::setHardspacing()
{
  hardSpacing_ = 1;
}

void lefiNonDefault::addUseVia(const char* name)
{
  if (numUseVias_ == allocatedUseVias_) {
    int i;
    char** vn;

    if (allocatedUseVias_ == 0) {
      allocatedUseVias_ = 2;
    } else {
      allocatedUseVias_ *= 2;
    }
    vn = (char**) lefMalloc(sizeof(char*) * allocatedUseVias_);
    for (i = 0; i < numUseVias_; i++) {
      vn[i] = useViaName_[i];
    }
    if (numUseVias_) {
      lefFree(useViaName_);
    }
    useViaName_ = vn;
  }
  useViaName_[numUseVias_] = (char*) lefMalloc(strlen(name) + 1);
  strcpy(useViaName_[numUseVias_], CASE(name));
  numUseVias_ += 1;
}

void lefiNonDefault::addUseViaRule(const char* name)
{
  if (numUseViaRules_ == allocatedUseViaRules_) {
    int i;
    char** vn;

    if (allocatedUseViaRules_ == 0) {
      allocatedUseViaRules_ = 2;
    } else {
      allocatedUseViaRules_ *= 2;
    }
    vn = (char**) lefMalloc(sizeof(char*) * allocatedUseViaRules_);
    for (i = 0; i < numUseViaRules_; i++) {
      vn[i] = useViaRuleName_[i];
    }
    if (numUseViaRules_) {
      lefFree(useViaRuleName_);
    }
    useViaRuleName_ = vn;
  }
  useViaRuleName_[numUseViaRules_] = (char*) lefMalloc(strlen(name) + 1);
  strcpy(useViaRuleName_[numUseViaRules_], CASE(name));
  numUseViaRules_ += 1;
}

void lefiNonDefault::addMinCuts(const char* name, int numCuts)
{
  if (numMinCuts_ == allocatedMinCuts_) {
    int i;
    char** cn;
    int* nc;

    if (allocatedMinCuts_ == 0) {
      allocatedMinCuts_ = 2;
    } else {
      allocatedMinCuts_ *= 2;
    }
    cn = (char**) lefMalloc(sizeof(char*) * allocatedMinCuts_);
    nc = (int*) lefMalloc(sizeof(int) * allocatedMinCuts_);
    for (i = 0; i < numMinCuts_; i++) {
      cn[i] = cutLayerName_[i];
      nc[i] = numCuts_[i];
    }
    if (numMinCuts_) {
      lefFree(cutLayerName_);
      lefFree(numCuts_);
    }
    cutLayerName_ = cn;
    numCuts_ = nc;
  }
  cutLayerName_[numMinCuts_] = (char*) lefMalloc(strlen(name) + 1);
  strcpy(cutLayerName_[numMinCuts_], CASE(name));
  numCuts_[numMinCuts_] = numCuts;
  numMinCuts_ += 1;
}

void lefiNonDefault::end()
{
  // Return the callbacks to their normal state.
  // lefrSetViaCbk((lefrViaCbkFnType)oldViaCbk_);
  // lefrSetSpacingCbk((lefrSpacingCbkFnType)oldSpacingCbk_);
  // lefrSetSpacingBeginCbk((lefrVoidCbkFnType)oldSpacingBeginCbk_);
  // lefrSetSpacingEndCbk((lefrVoidCbkFnType)oldSpacingEndCbk_);
  // lefrSetViaCbk(oldViaCbk);
  // lefrSetSpacingCbk(oldSpacingCbk);
  // lefrSetSpacingBeginCbk(oldSpacingBeginCbk);
  // lefrSetSpacingEndCbk(oldSpacingEndCbk);
  // pcr 909010 - global var lefData->nd is used to pass nondefault rule data
  // lefrSetUserData(oldUserData_);
  lefData->nd = nullptr;
}

int lefiNonDefault::numLayers() const
{
  return numLayers_;
}

const char* lefiNonDefault::layerName(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return nullptr;
  }
  return layerName_[index];
}

int lefiNonDefault::hasLayerWidth(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasWidth_[index];
}

double lefiNonDefault::layerWidth(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return width_[index];
}

int lefiNonDefault::hasLayerDiagWidth(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasDiagWidth_[index];
}

double lefiNonDefault::layerDiagWidth(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return diagWidth_[index];
}

int lefiNonDefault::hasLayerWireExtension(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasWireExtension_[index];
}

int lefiNonDefault::hasLayerSpacing(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasSpacing_[index];
}

double lefiNonDefault::layerWireExtension(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return wireExtension_[index];
}

double lefiNonDefault::layerSpacing(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return spacing_[index];
}

int lefiNonDefault::hasLayerResistance(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasResistance_[index];
}

double lefiNonDefault::layerResistance(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return resistance_[index];
}

int lefiNonDefault::hasLayerCapacitance(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasCapacitance_[index];
}

double lefiNonDefault::layerCapacitance(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return capacitance_[index];
}

int lefiNonDefault::hasLayerEdgeCap(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0;
  }
  return hasEdgeCap_[index];
}

double lefiNonDefault::layerEdgeCap(int index) const
{
  char msg[160];
  if (index < 0 || index >= numLayers_) {
    sprintf(msg,
            "ERROR (LEFPARS-1402): The index number %d given for the "
            "NONDEFAULT LAYER is invalid.\nValid index is from 0 to %d",
            index,
            numLayers_);
    lefiError(0, 1402, msg);
    return 0.0;
  }
  return edgeCap_[index];
}

int lefiNonDefault::numVias() const
{
  return numVias_;
}

lefiVia* lefiNonDefault::viaRule(int index) const
{
  char msg[160];
  if (index < 0 || index >= numVias_) {
    sprintf(msg,
            "ERROR (LEFPARS-1403): The index number %d given for the "
            "NONDEFAULT VIA is invalid.\nValid index is from 0 to %d",
            index,
            numVias_);
    lefiError(0, 1403, msg);
    return nullptr;
  }
  return viaRules_[index];
}

int lefiNonDefault::numSpacingRules() const
{
  return numSpacing_;
}

lefiSpacing* lefiNonDefault::spacingRule(int index) const
{
  char msg[160];
  if (index < 0 || index >= numSpacing_) {
    sprintf(msg,
            "ERROR (LEFPARS-1404): The index number %d given for the "
            "NONDEFAULT SPACING is invalid.\nValid index is from 0 to %d",
            index,
            numSpacing_);
    lefiError(0, 1404, msg);
    return nullptr;
  }
  return spacingRules_[index];
}

const char* lefiNonDefault::name() const
{
  return name_;
}

int lefiNonDefault::hasHardspacing() const
{
  return hardSpacing_;
}

int lefiNonDefault::numUseVia() const
{
  return numUseVias_;
}

const char* lefiNonDefault::viaName(int index) const
{
  char msg[160];
  if (index < 0 || index >= numUseVias_) {
    sprintf(msg,
            "ERROR (LEFPARS-1405): The index number %d given for the "
            "NONDEFAULT USE VIA is invalid.\nValid index is from 0 to %d",
            index,
            numUseVias_);
    lefiError(0, 1405, msg);
    return nullptr;
  }
  return useViaName_[index];
}

int lefiNonDefault::numUseViaRule() const
{
  return numUseViaRules_;
}

const char* lefiNonDefault::viaRuleName(int index) const
{
  char msg[160];
  if (index < 0 || index >= numUseViaRules_) {
    sprintf(msg,
            "ERROR (LEFPARS-1406): The index number %d given for the "
            "NONDEFAULT USE VIARULE is invalid.\nValid index is from 0 to %d",
            index,
            numUseViaRules_);
    lefiError(0, 1406, msg);
    return nullptr;
  }
  return useViaRuleName_[index];
}

int lefiNonDefault::numMinCuts() const
{
  return numMinCuts_;
}

const char* lefiNonDefault::cutLayerName(int index) const
{
  char msg[160];
  if (index < 0 || index >= numMinCuts_) {
    sprintf(msg,
            "ERROR (LEFPARS-1407): The index number %d given for the "
            "NONDEFAULT CUT is invalid.\nValid index is from 0 to %d",
            index,
            numMinCuts_);
    lefiError(0, 1407, msg);
    return nullptr;
  }
  return cutLayerName_[index];
}

int lefiNonDefault::numCuts(int index) const
{
  char msg[160];
  if (index < 0 || index >= numMinCuts_) {
    sprintf(msg,
            "ERROR (LEFPARS-1407): The index number %d given for the "
            "NONDEFAULT CUT is invalid.\nValid index is from 0 to %d",
            index,
            numMinCuts_);
    lefiError(0, 1407, msg);
    return 0;
  }
  return numCuts_[index];
}

void lefiNonDefault::print(FILE* f)
{
  int i;
  lefiSpacing* s;
  lefiVia* v;

  fprintf(f, "Nondefault rule %s\n", name());
  fprintf(f,
          "%d layers   %d vias   %d spacing rules\n",
          numLayers(),
          numVias(),
          numSpacingRules());

  for (i = 0; i < numLayers(); i++) {
    fprintf(f, "  Layer %s\n", layerName(i));
    if (hasLayerWidth(i)) {
      fprintf(f, "    WIDTH %g\n", layerWidth(i));
    }
    if (hasLayerDiagWidth(i)) {
      fprintf(f, "    DIAGWIDTH %g\n", layerDiagWidth(i));
    }
    if (hasLayerSpacing(i)) {
      fprintf(f, "    SPACING %g\n", layerSpacing(i));
    }
    if (hasLayerWireExtension(i)) {
      fprintf(f, "    WIREEXTENSION %g", layerWireExtension(i));
    }
    if (hasLayerResistance(i)) {
      fprintf(f, "    RESISTANCE RPERSQ %g\n", layerResistance(i));
    }
    if (hasLayerCapacitance(i)) {
      fprintf(f, "    CAPACITANCE CPERSQDIST %g\n", layerCapacitance(i));
    }
    if (hasLayerEdgeCap(i)) {
      fprintf(f, "    EDGECAPACITANCE %g\n", layerEdgeCap(i));
    }
  }

  for (i = 0; i < numVias(); i++) {
    v = viaRule(i);
    v->print(f);
  }

  for (i = 0; i < numSpacingRules(); i++) {
    s = spacingRule(i);
    s->print(f);
  }
}

int lefiNonDefault::numProps() const
{
  return numProps_;
}

void lefiNonDefault::addProp(const char* name,
                             const char* value,
                             const char type)
{
  int len = strlen(name) + 1;
  if (numProps_ == propsAllocated_) {
    int i;
    int max;
    int lim = numProps_;
    char** nn;
    char** nv;
    double* nD;
    char* nt;

    if (propsAllocated_ == 0) {
      max = propsAllocated_ = 2;
    } else {
      max = propsAllocated_ *= 2;
    }
    nn = (char**) lefMalloc(sizeof(char*) * max);
    nv = (char**) lefMalloc(sizeof(char*) * max);
    nD = (double*) lefMalloc(sizeof(double) * max);
    nt = (char*) lefMalloc(sizeof(char) * max);
    for (i = 0; i < lim; i++) {
      nn[i] = names_[i];
      nv[i] = values_[i];
      nD[i] = dvalues_[i];
      nt[i] = types_[i];
    }
    lefFree(names_);
    lefFree(values_);
    lefFree(dvalues_);
    lefFree(types_);
    names_ = nn;
    values_ = nv;
    dvalues_ = nD;
    types_ = nt;
  }
  names_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
  strcpy(names_[numProps_], name);
  len = strlen(value) + 1;
  values_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
  strcpy(values_[numProps_], value);
  dvalues_[numProps_] = 0;
  types_[numProps_] = type;
  numProps_ += 1;
}

void lefiNonDefault::addNumProp(const char* name,
                                const double d,
                                const char* value,
                                const char type)
{
  int len = strlen(name) + 1;
  if (numProps_ == propsAllocated_) {
    int i;
    int max;
    int lim = numProps_;
    char** nn;
    char** nv;
    double* nD;
    char* nt;

    if (propsAllocated_ == 0) {
      max = propsAllocated_ = 2;
    } else {
      max = propsAllocated_ *= 2;
    }
    nn = (char**) lefMalloc(sizeof(char*) * max);
    nv = (char**) lefMalloc(sizeof(char*) * max);
    nD = (double*) lefMalloc(sizeof(double) * max);
    nt = (char*) lefMalloc(sizeof(char) * max);
    for (i = 0; i < lim; i++) {
      nn[i] = names_[i];
      nv[i] = values_[i];
      nD[i] = dvalues_[i];
      nt[i] = types_[i];
    }
    lefFree(names_);
    lefFree(values_);
    lefFree(dvalues_);
    lefFree(types_);
    names_ = nn;
    values_ = nv;
    dvalues_ = nD;
    types_ = nt;
  }
  names_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
  strcpy(names_[numProps_], name);
  len = strlen(value) + 1;
  values_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
  strcpy(values_[numProps_], value);
  dvalues_[numProps_] = d;
  types_[numProps_] = type;
  numProps_ += 1;
}

const char* lefiNonDefault::propName(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return nullptr;
  }
  return names_[index];
}

const char* lefiNonDefault::propValue(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return nullptr;
  }
  return values_[index];
}

double lefiNonDefault::propNumber(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return 0;
  }
  return dvalues_[index];
}

char lefiNonDefault::propType(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return 0;
  }
  return types_[index];
}

int lefiNonDefault::propIsNumber(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return 0;
  }
  return dvalues_[index] ? 1 : 0;
}

int lefiNonDefault::propIsString(int index) const
{
  char msg[160];
  if (index < 0 || index >= numProps_) {
    sprintf(msg,
            "ERROR (LEFPARS-1408): The index number %d given for the "
            "NONDEFAULT PROPERTY is invalid.\nValid index is from 0 to %d",
            index,
            numProps_);
    lefiError(0, 1408, msg);
    return 0;
  }
  return dvalues_[index] ? 0 : 1;
}
END_LEF_PARSER_NAMESPACE
